/*
 * $Id: ProcessorMDPImpl.java,v 1.28 2011/11/18 19:38:33 navdeep_mahajan Exp $
 * 
 * Copyright (C) 2008 General Electric Company. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of the General
 * Electric Company (GE). You shall not disclose this software and shall use it
 * only in accordance with the terms of the license agreement you entered into
 * with GE.
 * 
 * GE MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
 * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 * NON-INFRINGEMENT. GE SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING, OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES.
 */
package com.ge.healthcare.autosc.processor;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import com.ge.healthcare.autosc.common.ASCLogger;
import com.ge.healthcare.autosc.common.ASCUtil;
import com.ge.healthcare.autosc.common.database.dao.IStepTypeDAO;
import com.ge.healthcare.autosc.common.database.dao.ITaskCategoryInfoDAO;
import com.ge.healthcare.autosc.common.database.pojo.ActTask;
import com.ge.healthcare.autosc.common.database.pojo.CfgCodeDetails;
import com.ge.healthcare.autosc.common.database.pojo.CfgTaskCategoryInfo;
import com.ge.healthcare.autosc.common.dbLogger.StepLogger;
import com.ge.healthcare.autosc.common.message.AutoSCBasicMDP;
import com.ge.healthcare.autosc.common.message.sender.MessageSender;
import com.ge.healthcare.autosc.processor.dispatcher.TaskDispatcher;
import com.ge.healthcare.autosc.processor.exception.ProcessorMDPException;
import com.ge.healthcare.autosc.processor.exception.TaskDispatcherException;
import com.ge.healthcare.autosc.processor.exception.TaskException;

/**
 * 
 * @author 212042946
 * 
 */
public class ProcessorMDPImpl extends AutoSCBasicMDP implements ProcessorMDP,
		InitializingBean {

	private static TaskDispatcher dispatcher;
	private static IStepTypeDAO iStepTypeDAO = null;
	private static MessageSender messageSender = null;
	private static MessageSender trrMsgSender = null;
	private static String stepTypeName = null;
	private static ITaskCategoryInfoDAO taskCategoryInfoDAO = null;

	public ProcessorMDPImpl() {
	}

	/**
	 * Spring Bean cycle method
	 */
	public void afterPropertiesSet() throws Exception {
		Assert.notNull(taskDAO, assertErrorMessage("ActTaskDAO"));
		Assert.notNull(codeDAO, assertErrorMessage("CodeDAO"));
		Assert.notNull(iStepTypeDAO, assertErrorMessage("StepTypeDAO"));
		Assert.notNull(messageSender, assertErrorMessage("MessageSender"));
		Assert.notNull(trrMsgSender, assertErrorMessage("TrrMsgSender"));
		Assert.notNull(stepTypeName, assertErrorMessage("StepTypeName"));
	}

	/**
	 * Process the task
	 * 
	 * @param actTask
	 *            task object
	 */
	public void processTaskInfo(ActTask actTask) {
		String methodName = "processTaskInfo";
		startStepLog(actTask, PrcCodeConstants.PRC_P_APP_000);
		// During the creation time, everything is good... successful.
		ActTask prcActTask = null;

		try {
			ASCLogger.info(this.getClass(), methodName, "Received task:"
					+ actTask);
			prcActTask = taskDAO.getTaskByID(actTask.getTaskId());
			setTaskCode(prcActTask, PrcCodeConstants.PRC_P_APP_000);
			// If the code is not about JMS error, then process the task.
			if (isRedelivery(prcActTask) == false) {
				StepLogger
						.addStepLog("Receive and process task with task type "
								+ prcActTask.getTaskType());
				updateStepType(prcActTask);
				dispatcher.processTask(prcActTask);
				StepLogger.addStepLog(new StringBuffer()
						.append("Task with task type ")
						.append(prcActTask.getTaskType())
						.append(" is processed successfully.").toString());
				setCurrentCodeId(PrcCodeConstants.PRC_S_APP_000);
			} else {
				StepLogger
						.addStepLog("Receive and re-deliver task with task type "
								+ prcActTask.getTaskType());
			}
		} catch (TaskDispatcherException tde) {
			ASCLogger.error(
					this.getClass(),
					methodName,
					new StringBuffer()
							.append("Failed to process task. Error code: ")
							.append(tde.getErrorCode()).append(" Task:")
							.append(prcActTask), tde);
			StepLogger.addStepLog(new StringBuffer()
					.append("Failed to process task. Error Code:")
					.append(tde.getErrorCode()).append(" Exception ")
					.append(tde.getMessage()).toString());
			setCurrentCodeId(tde.getErrorCode());
		} catch (ProcessorMDPException pe) {
			StepLogger.addStepLog("Failed to process task. Exception "
					+ pe.getMessage());
			setCurrentCodeId(PrcCodeConstants.PRC_F_APP_001);
			ASCLogger.error(this.getClass(), methodName, new StringBuffer()
					.append("Failed to process task. ").append(" Task:")
					.append(prcActTask), pe);
		} catch (TaskException te) {
			ASCLogger.error(
					this.getClass(),
					methodName,
					new StringBuffer()
							.append("Failed to process task. Error code: ")
							.append(te.getErrorCode()).append(" Task:")
							.append(prcActTask), te);
			StepLogger.addStepLog("Failed to process task. Exception "
					+ te.getMessage());
			setCurrentCodeId(te.getErrorCode());
		} catch (RuntimeException re) {
			StepLogger
					.addStepLog(new StringBuffer()
							.append("Failed to process task with unknown error. Please contact support team. Exception:")
							.append(re).append("\n")
							.append(ASCUtil.getStackTrace(re)).toString());
			ASCLogger.fatal(this.getClass(), methodName, new StringBuffer()
					.append("Failed to process task. ").append(prcActTask)
					.toString(), re);
			setCurrentCodeId(PrcCodeConstants.PRC_F_SYS_000);
		} finally {
			if (prcActTask != null) {
				actTask = prcActTask;
			}
			try {
				setTaskCode(actTask);
			} catch (RuntimeException re) {
				ASCLogger.error(this.getClass(), methodName,
						"Got exception in finally while setting task code", re);
			}
			try {
				ASCLogger.debug(this.getClass(), methodName,
						"Sending notification to lbs for task:" + actTask);
				CfgTaskCategoryInfo taskCategoryInfo = taskCategoryInfoDAO
						.getTaskCategoryForTaskType(actTask.getTaskType());
				if (!taskCategoryInfo.isUnRegulatedTaskCategory()) {
					trrMsgSender.sendToQueue(actTask);
				}
			} catch (RuntimeException re) {
				StepLogger
						.addStepLog("Failed to release System Resource, will retry..");
				setTaskCode(actTask, PrcCodeConstants.PRC_F_APP_003);
				ASCLogger.error(this.getClass(), methodName,
						"Exception: " + re.getMessage(), re);
			}
			try {
				setTaskCode(actTask);
				ASCLogger.debug(this.getClass(), methodName,
						"Sending notification to dispatcher for task:"
								+ actTask);
				messageSender.sendToQueue(actTask);

			} catch (RuntimeException re) {
				StepLogger
						.addStepLog("Failed to report task completion status, will retry..");
				setTaskCode(actTask, PrcCodeConstants.PRC_F_APP_003);
				ASCLogger.error(this.getClass(), methodName,
						"Exception: " + re.getMessage(), re);
			}
			try {
				stepLoggerEnd(actTask, PrcCodeConstants.PRC_F_SYS_000);
			} catch (RuntimeException re) {
				ASCLogger.error(this.getClass(), methodName,
						"Got exception in logEndProcessing", re);
			}
		}
	}

	/**
	 * Set the task dispatcher
	 * 
	 * @param taskDispatcher
	 *            TaskDispatcher object
	 */
	public void setTaskDispatcher(TaskDispatcher taskDispatcher) {
		ProcessorMDPImpl.dispatcher = taskDispatcher;
	}

	/**
	 * Set stepTypeDAO
	 * 
	 * @param stepTypeDAO
	 */
	public void setStepTypeDAO(IStepTypeDAO stepTypeDAO) {
		ProcessorMDPImpl.iStepTypeDAO = stepTypeDAO;
	}

	/**
	 * Set step type name
	 * 
	 * @param stepTypeName
	 */
	public void setStepTypeName(String stepTypeName) {
		ProcessorMDPImpl.stepTypeName = stepTypeName;
	}

	/**
	 * Set message sender
	 * 
	 * @param messageSender
	 */
	public void setMessageSender(MessageSender messageSender) {
		ProcessorMDPImpl.messageSender = messageSender;
	}

	/*
	 * Is the task is just for re-delivery
	 */
	private boolean isRedelivery(ActTask actTask) {
		boolean status = false;
		Long codeId = actTask.getCodeId();
		if (codeId != null) {
			CfgCodeDetails codeDetails = codeDAO.getCodeDetailsByID(codeId);
			if (codeDetails != null) {
				if (PrcCodeConstants.PRC_F_APP_003.equals(codeDetails
						.getCodeName())) {
					status = true;
				}
			}
		}
		return status;
	}

	private String assertErrorMessage(String missingObject) {
		StringBuffer msg = new StringBuffer(missingObject);
		msg.append(" is required. Use set").append("missingObject");
		msg.append("() to provide one");
		return msg.toString();
	}

	/**
	 * @param trrMsgSender
	 *            the trrMsgSender to set
	 */
	public void setTrrMsgSender(MessageSender trrMsgSender) {
		ProcessorMDPImpl.trrMsgSender = trrMsgSender;
	}

	/**
	 * @param taskCategoryInfoDAO
	 *            the taskCategoryInfoDAO to set
	 */
	public void setTaskCategoryInfoDAO(ITaskCategoryInfoDAO taskCategoryInfoDAO) {
		ProcessorMDPImpl.taskCategoryInfoDAO = taskCategoryInfoDAO;
	}

}
